package model.doe;

import java.awt.Color;
import java.awt.image.BufferedImage;

import model.coding.Coding;
import model.util.CodingUtil;

public abstract class AbstractDoe {
	protected int formDoe;
	public static final int DOE_FORM_ANNULAR = 0;
	public static final int DOE_FORM_CYLINDRICAL = 1;
	public static final int DOE_FORM_CROSSED = 2;
	public static final int DOE_FORM_NON_SYMMETRIC = 3;

	private double[][] complexMatrix;

	protected int widthPointsNumber;
	protected int heightPointsNumber;
	protected double maximumValue = 0;
	public double minValue = 0;

	public void setDoeFormType(int doeFormType) {
		this.formDoe = doeFormType;
	}

	public int getDoeFormType() {
		return formDoe;
	}

	public abstract double run(int i, int j);

	double[][] getMatrix(int matrixType) {
		int widthOffset = widthPointsNumber / 2;
		int heightOffset = heightPointsNumber / 2;
		double[][] matrix = new double[widthOffset * 2][heightOffset * 2];
		complexMatrix = new double[widthOffset * 2][heightOffset * 2];
		for (int i = -widthOffset; i < widthOffset; i++) {
			for (int j = -heightOffset; j < heightOffset; j++) {
				switch (matrixType) {
				case MatrixType.ABSOLUTE_AMPLITUDE: {

					matrix[i + widthOffset][j + heightOffset] = getAbsoluteAmplitudeFromComplexValue(i, j);
					break;
				}
				case MatrixType.SIGN_PHASE: {
					matrix[i + widthOffset][j + heightOffset] = getSingPhaseFromComplexValue(i, j);
					break;
				}
				case MatrixType.FROM_PHASE_TO_2_PI_M:{
					
					matrix[i + widthOffset][j + heightOffset] = CodingUtil.CodingPhaseTo2Pi(run(i, j), maximumValue, minValue, 1);
					break;
				}
				}
				if (Math.abs(matrix[i + widthOffset][j + heightOffset])> maximumValue){
					maximumValue = Math.abs(matrix[i + widthOffset][j + heightOffset]);
				}
				complexMatrix[i + widthOffset][j + heightOffset] = getComplexValue(i, j);
			}
		}
		return matrix;
	}

	private double getComplexValue(int i, int j) {
		return run(i, j);

	}

	private double getSingPhaseFromComplexValue(int i, int j) {
		return run(i, j) > 0 ? Math.PI : -Math.PI;

	}

	private double getAbsoluteAmplitudeFromComplexValue(int i, int j) {
		return Math.abs(run(i, j));

	}

	@Deprecated
	private int[][] normToMaxValue(double[][] matrix) {

		int[][] normedMatrix = new int[widthPointsNumber][heightPointsNumber];
		for (int i = 0; i < widthPointsNumber; i++) {
			for (int j = 0; j < heightPointsNumber; j++) {
				/*int transparency = (int) (matrix[i][j] / Math.PI* 255)<<24;
				int color = 0xffffff+transparency;*/
				normedMatrix[i][j] = (int) (matrix[i][j] / Math.PI * 255);

			}
		}
		return normedMatrix;
	}

	private int[][] normToMaxAmplitudeValue(double[][] matrix) {

		int[][] normedMatrix = new int[widthPointsNumber][heightPointsNumber];
		for (int i = 0; i < widthPointsNumber; i++) {
			for (int j = 0; j < heightPointsNumber; j++) {
				//int transparency = (int) (matrix[i][j]/ maximumValue* 255)<<24;
				//int color = 0xffffff+transparency;
				normedMatrix[i][j] = (int) (matrix[i][j] / maximumValue * 255);

			}
		}
		return normedMatrix;
	}

	private int[][] normToMaxSignPhaseValue(double[][] matrix) {

		int[][] normedMatrix = new int[widthPointsNumber][heightPointsNumber];
		for (int i = 0; i < widthPointsNumber; i++) {
			for (int j = 0; j < heightPointsNumber; j++) {
				/*int transparency = (int) (((matrix[i][j]+ Math.PI) / Math.PI )* 255)<<24;
				int color = 0xffffff+transparency;*/
				normedMatrix[i][j] = (int) (((matrix[i][j]+ Math.PI) / Math.PI )* 255);
			}
		}
		return normedMatrix;
	}

	public BufferedImage getAbsoluteAmplitudeImage() {

		int[][] tempImageMatrix = normToMaxAmplitudeValue(getMatrix(MatrixType.ABSOLUTE_AMPLITUDE));
		return getImage(tempImageMatrix);

	}

	public BufferedImage getPhaseTo2PiMImage() {
		int[][] tempImageMatrix = normToMaxValue(getMatrix(MatrixType.FROM_PHASE_TO_2_PI_M));
		return getImage(tempImageMatrix);
	}

	public BufferedImage getSignPhaseImage() {

		int[][] tempImageMatrix = normToMaxSignPhaseValue(getMatrix(MatrixType.SIGN_PHASE));
		return getImage(tempImageMatrix);

	}

	public BufferedImage getImage(int[][] tempImageMatrix) {
		BufferedImage img = new BufferedImage(widthPointsNumber, heightPointsNumber,
				BufferedImage.TYPE_INT_BGR);
		for (int i = 0; i < this.widthPointsNumber ; i++) {
			for (int j = 0; j < this.heightPointsNumber ; j++) {
				img.setRGB(i, j, (int) (tempImageMatrix[i][j]));
			}
		}

		return img;
	}

	public double [][] getAbsoluteAmplitudeMatrix() {

		getMatrix(MatrixType.ABSOLUTE_AMPLITUDE);
		double[][] amplitudeMatrix = new double[widthPointsNumber][heightPointsNumber];
		for (int i = 0; i < widthPointsNumber; i++) {
			for (int j = 0; j < heightPointsNumber; j++) {
				amplitudeMatrix[i][j] = (float)Math.abs(complexMatrix[i][j]);
			}
		}
		return amplitudeMatrix;
	}
	
	public double [][] getPhaseTo2PIMatrix() {

		double[][] amplitudeMatrix = new double[widthPointsNumber][heightPointsNumber];
		for (int i = 0; i < widthPointsNumber; i++) {
			for (int j = 0; j < heightPointsNumber; j++) {
				amplitudeMatrix[i][j] = (float)CodingUtil.CodingPhaseTo2Pi(complexMatrix[i][j], maximumValue, minValue, 1);
			}
		}
		return amplitudeMatrix;
	}

	public double [][] getSignPhaseMatrix() {

		double[][] signPhaseMatrix = new double[widthPointsNumber][heightPointsNumber];
		for (int i = 0; i < widthPointsNumber ; i++) {
			for (int j = 0; j < heightPointsNumber; j++) {
				signPhaseMatrix[i][j] = complexMatrix[i][j] < 0 ? (float)Math.PI : 0f;
			}
		}
		return signPhaseMatrix;
	}

	public int getWidthPointsNumber() {
		return widthPointsNumber;
	}

	public int getHeightPointsNumber() {
		return heightPointsNumber;
	}
}